<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<input type="text" id="inputValue"/>
<button id="btn">打开/创建database</button>
<br>
<button id="nextBtn">正序索引游标获取所有</button>
<br>
<button id="prevBtn">倒序索引游标获取所有</button>
<br>
<button id="nextUniqueBtn">正序索引游标获取所有（去除重复）</button>
<br>
<button id="prevUniqueBtn">倒序索引游标获取所有（去除重复）</button>
<br>
<button id="keyRangeOnlyBtn">只获取Tony</button>
<br>
<button id="keyRangeBtn">只获取Donna~Yoga范围内的</button>
<script>
  // 我们的客户数据看起来像这样。
  const customerData = [
    {ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com"},
    {ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org"},
    {ssn: "666-66-6666", name: "Tony", age: 23, email: "ony@home.org"},
    {ssn: "888-88-8888", name: "Donna", age: 27, email: "donna2@home.org"},
    {ssn: "999-99-9999", name: "Yoga", age: 18, email: "yoga@home.org"}
  ];
  let db = null
  const openDatabase = function (version) {
    console.log('database version:', version)
    // 如果数据库不存在，open 操作会创建该数据库,第二个参数指定数据库的版本
    const request = window.indexedDB.open('MySecondDatabase', version)

    request.onsuccess = function (event) {
      db = event.target.result
      console.log('database success')
    }

    request.onerror = function (event) {
      console.log('database fail:', event.target.error.message)
    }

    // 当你创建一个新的数据库或者增加已存在的数据库的版本号（当打开数据库时，指定一个比之前更大的版本号）， onupgradeneeded 事件会被触发
    request.onupgradeneeded = function (event) {
      console.log('database onupgradeneeded')

      // 保存 IDBDataBase 接口
      db = event.target.result
      const objectStore = db.createObjectStore('customers', {keyPath: 'ssn'})

      /**
       * 使用 SSN 作为键来存储客户数据是合理的，因为 SSN 唯一地标识了一个个体（对隐私来说这是否是一个好的想法是另外一个话题，不在本文的讨论范围内）。
       * 如果你想要通过姓名来查找一个客户，那么，你将需要在数据库中迭代所有的 SSN 直到你找到正确的那个。
       * 以这种方式来查找将会非常的慢，相反你可以使用索引。
       */
      // 建立一个索引来通过姓名来搜索客户。名字可能会重复，所以我们不能使用 unique 索引
      objectStore.createIndex("name", "name", {unique: false});
      // email不允许重复
      objectStore.createIndex('email', 'email', {unique: true})

      // 使用事务的 oncomplete 事件确保在插入数据前对象仓库已经创建完毕
      objectStore.transaction.oncomplete = function () {
        const transaction = db.transaction('customers', 'readwrite')
        const customersObjectStore = transaction.objectStore('customers')
        customerData.forEach(item => {
          customersObjectStore.add(item)
        })
      }
    }
  }

  btn.addEventListener('click', () => {
    openDatabase(Number(inputValue.value || 1))
  })

  const getData = (keyRang = null, direction = 'next') => {
    const index = db
      .transaction('customers')
      .objectStore('customers')
      .index('name')
    const data = []
    index.openCursor(keyRang, direction).onsuccess = function (event) {
      const cursor = event.target.result
      if (cursor) {
        // cursor.key 是一个 name, 就像 "Bill", 然后 cursor.value 是整个对象。
        data.push(cursor.value)
        cursor.continue()
      } else {
        console.log('get data:')
        console.log(data)
      }
    }
  }

  nextBtn.addEventListener('click', () => {
    getData()
  })

  prevBtn.addEventListener('click', () => {
    // 游标展示所有记录，包括重复的记录。它从主键区间上界开始逐步往下移动（按主键的顺序单调递减）
    getData(null, 'prev')
  })

  nextUniqueBtn.addEventListener('click', () => {
    // 游标展示所有记录，不包括重复的记录。如果同一个主键存在重复的记录，只有第一条迭代记录被取出。它从主键区间的下界开始逐步上升
    getData(null, 'nextunique')
  })

  prevUniqueBtn.addEventListener('click', () => {
    getData(null, 'prevunique')
  })

  /**
   * 如果你想要限定你在游标中看到的值的范围，
   * 你可以使用一个 key range 对象然后把它作为第一个参数传给 openCursor() 或是 openKeyCursor()。
   * 你可以构造一个只允许一个单一 key 的 key range，或者一个具有下限或上限，或者一个既有上限也有下限。
   * 边界可以是“闭合的”（也就是说 key range 包含给定的值）或者是“开放的”（也就是说 key range 不包括给定的值）。
   */

  keyRangeOnlyBtn.addEventListener('click', () => {
    var boundKeyRange = IDBKeyRange.only("Tony");
    getData(boundKeyRange)
  })

  keyRangeBtn.addEventListener('click', () => {
    // 匹配所有在“Bill”和“Donna”之间的，但不包括“Donna” false：表示包含边界值， true：表示不包含边界值
    var boundKeyRange = IDBKeyRange.bound("Donna", "Yoga", false, false);
    console.log('boundKeyRange:', boundKeyRange)
    getData(boundKeyRange)
  })
</script>
</body>
</html>
